﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Server;
using Microsoft.TeamFoundation.Client;
using System.Net;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Framework.Client;
using System.Xml;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.Exchange.WebServices.Data;
using System.DirectoryServices.AccountManagement;

namespace CustomEventHandler
{
    public class EventNotification : ISubscriber
    {

        public string Name
        {
            get { return "WorkItemChangedEvent"; }
        }

        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.Normal; }
        }
        private string ReadSetting(string key)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(Path.GetPathRoot(Environment.SystemDirectory) + @"\Program Files\SSGS\TicketManager\TicketM\Configuration\TicketProcessingService.exe.config");
            XmlNode xmlnode = doc.DocumentElement;
            return doc.SelectSingleNode("/configuration/appSettings/add[@key='" + key + "']").Attributes["value"].Value;
        }

        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out Microsoft.TeamFoundation.Common.ExceptionPropertyCollection properties)
        {
            statusCode = 0;
            statusMessage = string.Empty;
            properties = null;
            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
                {
                    string machineName = System.Environment.MachineName;
                    string user = ReadSetting("UserName");
                    string password = ReadSetting("Password");
                    string ADdomain = ReadSetting("Domain");
                    NetworkCredential credential = new NetworkCredential(user, password, ADdomain);
                    TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://" + machineName + ":8080/tfs/" + ReadSetting("Collection")), credential);
                    TfsConfigurationServer configSvr = new TfsConfigurationServer(new Uri("http://" + machineName + ":8080/tfs"), credential);

                    ITeamFoundationRegistry regSvc = configSvr.GetService<ITeamFoundationRegistry>();
                    string smtpHost = regSvc.GetValue(@"/Service/Integration/Settings/SmtpServer");
                    string address = regSvc.GetValue(@"/Service/Integration/Settings/EmailNotificationFromAddress");

                    string AssignedTo, subject, message, domain = "";
                    WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent;
                    WorkItemStore ws = tpc.GetService<WorkItemStore>();
                    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi = ws.GetWorkItem(ev.CoreFields.IntegerFields[0].NewValue);
                    Project project = ws.Projects[ev.PortfolioProject];
                    #region General Notification of any Ticket assigned to team member
                    if (wi.Type == project.WorkItemTypes["Ticket"] && (wi.Fields["SSGS.AllowNotification"].Value.ToString() == "All" || (wi.Fields["SSGS.AllowNotification"].Value.ToString() == "Create Only" && wi.Fields["State"].OriginalValue.ToString() == "")) && Int32.Parse(wi.Fields["SSGS.MyEfforts"].Value.ToString()) != 0)
                    {
                        Logger.CreateLogEntry("message creation started");
                        subject = wi.Type.Name + " Assignment. ID:" + wi.Id;
                        
                        message = "<P>A Ticket has been assigned to you with following details</P>" + Environment.NewLine;
                        AssignedTo = wi.Fields["System.AssignedTo"].Value.ToString();

                        message += "<BR/>Reference #:" + wi.Id;
                        message += Environment.NewLine;
                        //message += "Component: eContracting" + Environment.NewLine;
                        message += "<BR/>Title: " + Environment.NewLine;
                        message += wi.Title + Environment.NewLine;
                        message += Environment.NewLine;
                        message += "<BR/>Description" + Environment.NewLine;
                        message += wi.Description + Environment.NewLine;
                        message += "<BR/>State: " + wi.State + Environment.NewLine;
                        string url = "http://" + ReadSetting("Tfs") + ":8080/tfs/" + ReadSetting("Collection") + "/" + project.Name + "/_workitems#id=" + wi.Id + "&_a=edit\">Open Ticket";
                        message += "<BR><a href=\"" + url + "</a>";
                        Logger.CreateLogEntry("Message created");
                        IIdentityManagementService ims = tpc.GetService<IIdentityManagementService>();

                        Microsoft.TeamFoundation.Framework.Client.TeamFoundationIdentity tfid =
                            ims.ReadIdentity(IdentitySearchFactor.DisplayName, AssignedTo,
                            MembershipQuery.Expanded, ReadIdentityOptions.IncludeReadFromSource);
                        domain = address.Substring(address.LastIndexOf("@") + 1);
                        string exchVer = ReadSetting("ExVer");
                        using (var context = new PrincipalContext(ContextType.Domain, domain))
                        {
                            //read exchange server version from app file and accordingly create instance
                            ExchangeService exchService = null;

                            switch (exchVer)
                            {
                                case "Exchange 2007 SP1":
                                    exchService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
                                    break;
                                case "Exchange 2010":
                                    exchService = new ExchangeService(ExchangeVersion.Exchange2010);
                                    break;
                                case "Exchange 2010 SP1":
                                    exchService = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
                                    break;
                                case "Exchange 2010 SP2":
                                    exchService = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
                                    break;
                                case "Exchange 2013":
                                    exchService = new ExchangeService(ExchangeVersion.Exchange2013);
                                    break;
                                default:
                                    break;
                            }
                            Logger.CreateLogEntry("exchange server selected");
                            //ExchangeService exchService = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
                            NetworkCredential credentials = new NetworkCredential(user, password, ADdomain);
                            string exchUrl = "https://" + smtpHost + "/EWS/Exchange.asmx";
                            Logger.CreateLogEntry(exchUrl);
                            exchService.Url = new Uri(exchUrl);
                            exchService.Credentials = credentials;
                            ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
                            var userPrincipal = UserPrincipal.FindByIdentity(context, System.DirectoryServices.AccountManagement.IdentityType.Sid, tfid.Descriptor.Identifier);
                            EmailMessage mailMsg = new EmailMessage(exchService);
                            mailMsg.From = address;
                            mailMsg.ToRecipients.Add(userPrincipal.EmailAddress);
                            mailMsg.Subject = subject;
                            mailMsg.Body = message;
                            mailMsg.Send();
                            Logger.CreateLogEntry("Mail Sent to user " + user );

                        }
                    }
                    #endregion
                    RevisionCollection revColl = wi.Revisions;
                    Revision LatestRev = null;
                    foreach (Revision Rev in revColl)
                    {
                        LatestRev = Rev;
                    }

                    //TfsLog.WriteEntry(LatestRev.Fields["System.AssignedTo"].Value.ToString() + " : " + LatestRev.Fields["System.AssignedTo"].OriginalValue.ToString());
                    if (wi.Type == project.WorkItemTypes["Ticket"] && (LatestRev.Fields["System.AssignedTo"].Value.ToString() != LatestRev.Fields["System.AssignedTo"].OriginalValue.ToString()))
                    {
                        wi.Fields["SSGS.MyEfforts"].Value = 0;
                        wi.Save();
                        Logger.CreateLogEntry("work item saved " + wi.Title);
                    }
                }
            }
            catch(Exception ex)
            {
                string ErrLog = "!!EERROR while sending Ticket state change notifications: " + ex.Message + ex.StackTrace;
                if (ex.InnerException != null)
                {
                    ErrLog += ex.InnerException.Message;
                }
                Logger.CreateLogEntry(ErrLog);
            }

              return EventNotificationStatus.ActionApproved;
        }

        public Type[] SubscribedTypes()
        {
            return new Type[] { typeof(WorkItemChangedEvent) };
        }

        private static bool CertificateValidationCallBack(
                     object sender,
                     System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                     System.Security.Cryptography.X509Certificates.X509Chain chain,
                     System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            // If the certificate is a valid, signed certificate, return true.
            if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
            {
                return true;
            }
            // If there are errors in the certificate chain, look at each error to determine the cause.
            if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
            {
                if (chain != null && chain.ChainStatus != null)
                {
                    foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
                    {
                        if ((certificate.Subject == certificate.Issuer) &&
                                           (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                        {
                            // Self-signed certificates with an untrusted root are valid. 
                            continue;
                        }
                        else
                        {
                            if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                            {
                                // If there are any other errors in the certificate chain, the certificate is invalid,
                                // so the method returns false.
                                return false;
                            }
                        }
                    }
                }
                // When processing reaches this line, the only errors in the certificate chain are 
                // untrusted root errors for self-signed certificates. These certificates are valid
                // for default Exchange server installations, so return true.
                return true;
            }
            else
            {
                // In all other cases, return false.
                return false;
            }
        }
    }
    class Logger
    {
        public static void CreateLogEntry(string Message)
        {
            String LogPath = Path.GetPathRoot(Environment.SystemDirectory) + @"\Program Files\SSGS\Logs";
            if (!Directory.Exists(LogPath))
                Directory.CreateDirectory(LogPath);
            string FileName = DateTime.Now.Month.ToString() + DateTime.Now.Year.ToString() + ".log";
            if (!File.Exists(LogPath + "\\" + FileName))
                File.CreateText(LogPath + "\\" + FileName);
            StreamWriter log = File.AppendText(LogPath + "\\" + FileName);
            log.WriteLine(Message);
            log.Flush();
            log.Close();
        }

    }
}
